﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;

namespace TempCtr.Model
{
    public class ThermostatSerialPort
    {
        #region 事件
        public delegate void NewDataDel(byte Thermostat_Addr, byte Cmd, int Data_Length, int TData);
        /// <summary>
        /// 新消息事件
        /// </summary>
        public event NewDataDel NewDataEvent;
        private void RaiseEvent(byte Thermostat_Addr, byte Cmd, int Data_Length, int TData)
        {
            if (NewDataEvent == null) return;
            NewDataEvent(Thermostat_Addr, Cmd, Data_Length, TData);
        }

        public delegate void WaitingTimeOutDel(int Addr, byte Cmd);
        /// <summary>
        /// 回复超时事件
        /// </summary>
        public static event WaitingTimeOutDel WaitingTimeOutEvent;
        private static void WaitingTimeOut_RaiseEvent(int ID, byte Cmd)
        {
            if (WaitingTimeOutEvent == null) return;
            WaitingTimeOutEvent(ID, Cmd);
        }
        #endregion


       

        public static byte[] TxBuffer = new byte[8];

        public static List<int> WaitingReplyList = new List<int>();

        

        /// <summary>
        /// CRC校验 输入校验
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static bool CRC16In(byte[] bytes)
        {
            try
            {
                //计算并填写CRC校验码
                int crc = 0xffff;
                int len = bytes.Length;
                for (int n = 0; n < len - 2; n++)
                {
                    byte i;
                    crc = crc ^ bytes[n];
                    for (i = 0; i < 8; i++)
                    {
                        int TT;
                        TT = crc & 1;
                        crc = crc >> 1;
                        crc = crc & 0x7fff;
                        if (TT == 1)
                        {
                            crc = crc ^ 0xa001;
                        }
                        crc = crc & 0xffff;
                    }
                }
                if (bytes[len - 2] == (byte)((crc & 0xff)) &&  bytes[len - 1] == (byte)((crc >> 8) & 0xff))
                {
                    return true;
                }
                return false;
            }
            catch
            {
                return false;
            }

        }
        /// <summary>
        /// CRC校验 输出校验
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static void CRC16Out(byte[] bytes)
        {
            //计算并填写CRC校验码
            int crc = 0xffff;
            int len = bytes.Length;
            try
            {
                for (int n = 0; n < len - 2; n++)
                {
                    byte i;
                    crc = crc ^ bytes[n];
                    for (i = 0; i < 8; i++)
                    {
                        int TT;
                        TT = crc & 1;
                        crc = crc >> 1;
                        crc = crc & 0x7fff;
                        if (TT == 1)
                        {
                            crc = crc ^ 0xa001;
                        }
                        crc = crc & 0xffff;
                    }
                }
                bytes[len - 2] = (byte)((crc & 0xff));
                bytes[len - 1] = (byte)((crc >> 8) & 0xff);
            }
            catch (Exception ex)
            {
                //MainFrom.Logger.Error("校验crc函数错误"+ex.ToString());
            }
            
        }

        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="Port"></param>
        /// <param name="BaudRate"></param>
        /// <returns></returns>
        public bool Connect(SerialPort serialPort ,string Port, int BaudRate)
        {
            try
            {
                if (!serialPort.IsOpen)
                {
                    serialPort.PortName = Port;
                    serialPort.BaudRate = BaudRate;
                    serialPort.DataBits = 8;
                    serialPort.Parity = Parity.None;
                    serialPort.StopBits = StopBits.Two;
                    serialPort.ReadBufferSize = 1024;

                    serialPort.Open();
                   // MainFrom.Logger.Info("**********串口" + Port.ToString() + "打开成功************");
                    return true;
                }
                else
                {
                    //MainFrom.Logger.Info("**********串口" + Port.ToString() + "已经打开************");
                    return false;
                }              
            }
            catch (Exception ex)
            {
                //MainFrom.Logger.Error("串口" + Port.ToString() + "打开错误 "+ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        /// <returns></returns>
        public bool DisConnect(SerialPort serialPort)
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close();
                return true;
            }
            return false;
        }

        

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="Thermostat_Addr">温控仪地址</param>
        /// <param name="Cmd">指令</param>
        /// <param name="Register_Addr">寄存器地址</param>
        /// <param name="Data">数据</param>
        /// <param name="Waiting_Time">等待返回时间</param>
        /// 如果Waiting_Time == 0 则为无需返回
        public static void Cmd_Operation(SerialPort serialPort,int id, byte Thermostat_Addr, byte Cmd,int Register_Addr,int Data = 0,int Waiting_Time = 0)
        {
            if (serialPort.IsOpen)
            {
                TxBuffer[0] = Thermostat_Addr;
                TxBuffer[1] = Cmd;
                TxBuffer[2] = (byte)(Register_Addr >> 8);
                TxBuffer[3] = (byte)(Register_Addr);
                TxBuffer[4] = (byte)(Data >> 8);
                TxBuffer[5] = (byte)(Data);
                CRC16Out(TxBuffer);
                try
                {
                    serialPort.Write(TxBuffer, 0, 8);
                }
                catch (Exception ex)
                {
                    //MainFrom.Logger.Error(id.ToString()+"  send error   "+ex.ToString());
                }
               

                if (Waiting_Time == 0) return;
                //防止回复超时
                WaitingReplyList.Add(id);
                Task t = new Task(() =>
                {
                    Thread.Sleep(Waiting_Time);
                    if(WaitingReplyList.Contains(id))
                    {
                        WaitingTimeOut_RaiseEvent(id, Cmd);//触发超时事件
                        WaitingReplyList.Remove(id);
                    }
                });
                t.Start();
            }
        }

    }
}
